package jehc.cloud.oauth.client.timer;

import cn.hutool.core.collection.CollectionUtil;
import jehc.cloud.common.base.BaseResult;
import jehc.cloud.common.util.GetClientIp;
import jehc.cloud.common.util.RestTemplateUtil;
import jehc.cloud.common.util.StringUtil;
import jehc.cloud.oauth.client.constant.Constant;
import jehc.cloud.oauth.client.util.HeartbeatAttributesUtil;
import jehc.cloud.oauth.client.util.LogbackAppender;
import jehc.cloud.oauth.client.util.SDKUtil;
import jehc.cloud.oauth.client.vo.AuthLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.util.*;

/**
 * @Desc 上报控制台
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Component
@Slf4j
@Order(-1)
public class EscalationConsole implements CommandLineRunner {

    private static final Integer times = 1000*60;//更新时间60分钟一次(1000*60*60)

    @Autowired
    RestTemplateUtil restTemplateUtil;

    @Autowired
    HeartbeatAttributesUtil heartbeatAttributesUtil;

    @Resource
    LogbackAppender initLogbackAppender;

//    @Resource
//    Environment environment;

    @Resource
    SDKUtil sdkUtil;

    @Override
    public void run(String... args) throws Exception {
        try {
            initLogbackAppender.init();//初始化logback日志
            while (true){
                try {
                    log.info("开始上报控制台...");
                    if(heartbeatAttributesUtil.isOmpCollencted()){
                        escalationConsole();
                    }else{
                        log.warn("无法连接OMP中心...");
                    }
                }catch (Exception e){
                    log.error("Author分析日志上报控制台失败，信息：{}",e);
                }finally {
                    Thread.sleep(times);
                }
            }
        }catch (Exception e){
            log.error("Author分析日志上报控制台失败，信息：{}",e);
        }
    }

    /**
     * 本次调度筛选出要被调度的file文件
     * @param fileList
     * @param fileName
     * @return
     */
    private File doFile(File[] fileList,String fileName){
        int line = -1;
        boolean checkStatus = false;
        if(null != fileList && !StringUtil.isEmpty(fileName)){
            for(int i = 0; i < fileList.length; i++){
                File file = fileList[i];
                line = i;
                if(file.getName().equals(fileName)){//判断偏移量
                    checkStatus = true;
                    break;
                }
            }
            if(fileList.length == line){
                return null;
            }else if(fileList.length == 1 && line != -1 && !checkStatus){
                return fileList[0];
            }else if((fileList.length - line)>1 && line != -1 && checkStatus){
                return fileList[line+1];
            }
        }
        return null;
    }

    /**
     *
     */
    private synchronized void escalationConsole(){
        try {
            File[] fileList = orderByDate(sdkUtil.getLogPath());
            if(null == fileList){
                log.info("没有要上报的授权监控日志");
               return;
            }
            Map<String,Object> map = getPersistenceHisLog();
            File file = null;
            Long recordTime = map.get("recordTime")==null?0L:new Long(""+map.get("recordTime"));//上次更新时间
            Long lines =  map.get("lines") == null?0L:new Long(""+map.get("lines"));//上次行数
            String fileName = map.get("fileName") == null?null:""+map.get("fileName");//上次更新的文件名称
            if(null == lines){
                lines = 0L;
            }
            if(StringUtil.isEmpty(fileName)){
                file = fileList[0];
                fileName = fileList[0].getName();
            }else{
                file = doFile(fileList,fileName);
                if(null != file){
                    fileName = file.getName();
                }
            }
            if(null != file && !(Constant.AUTH_FILE_NAME+sdkUtil.getProjectName()+"-"+ GetClientIp.getLocalIp()+".log").equals(file.getName()) && !Constant.AUTH_PERSISTENCE_LOG_HIS_FILE_NAME.equals(file.getName())){
                BufferedReader in = new BufferedReader(new FileReader(sdkUtil.getLogPath()+"/"+fileName));
                String str;
                List<AuthLog> authInfoLogs = new ArrayList<>();
//                int currentNum = 0;
                while ((str = in.readLine()) != null) {
//                    currentNum++;
//                    //从上次记录开始
//                    if (lines>=currentNum){//如果上次记录行小于当前行则跳出
//                        break;
//                    }
                    String[] arr = str.split("\\|\\|");
                    String uri = arr[0];//访问地址
                    Long startTime = new Long(arr[1]);//开始时间
                    Long endTime = new Long(arr[2]);//结束时间
                    Long takeUpTime = (new Long(arr[2])-new Long(arr[1]));//耗时
                    String protocol = arr[3];//获取请求协议版本
                    String scheme = arr[4];//获取请求使用的协议名
                    String serverName = arr[5];//获取请求URL上的主机名（内网未转发时，一般为项目部署服务器主机ip）
                    String serverPort = arr[6];//获取请求URL上的端口号
                    String method = arr[7];//获取请求的方法
                    String localPort = arr[8];//获取最终接收请求的端口
                    String localName = arr[9];//获取最终接收请求的主机
                    String remoteAddr =arr[10];//获取发送请求的客户端地址（如果经过Apache等转发，则不是真实的DCN网地址）
                    String remoteHost = arr[11];//获取发送请求的客户端主机名
                    String remotePort = arr[12];//获取发送请求的客户端端口
                    AuthLog authInfoLog = new AuthLog();
                    authInfoLog.setUri(uri);
                    authInfoLog.setStartTime(startTime);
                    authInfoLog.setEndTime(endTime);
                    authInfoLog.setTakeUpTime(takeUpTime);
                    authInfoLog.setProtocol(protocol);
                    authInfoLog.setScheme(scheme);
                    authInfoLog.setServerName(serverName);
                    authInfoLog.setServerPort(serverPort);
                    authInfoLog.setMethod(method);
                    authInfoLog.setLocalPort(localPort);
                    authInfoLog.setLocalName(localName);
                    authInfoLog.setRemoteAddr(remoteAddr);
                    authInfoLog.setRemoteHost(remoteHost);
                    authInfoLog.setRemotePort(remotePort);
                    authInfoLogs.add(authInfoLog);
//                    lines++;//本次遍历的行数
                }
                recordTime = System.currentTimeMillis();
                if(!CollectionUtil.isEmpty(authInfoLogs)){
                    BaseResult baseResult = restTemplateUtil.post(restTemplateUtil.restOMPUrl() + Constant.OMP_AUTH_LOG_API,BaseResult.class,authInfoLogs);
                    if(baseResult.getSuccess()){
                        persistenceHisLog(sdkUtil.getLogPath(),Constant.AUTH_PERSISTENCE_LOG_HIS_FILE_NAME,recordTime+"||"+lines+"||"+fileName);//记录日志
                    }
                }
            }
        } catch (Exception e) {
            log.error("Author分析日志上报控制台异常：{}",e);
        }
    }

    /**
     * 记录本次上报后的日志记录 下次从该记录行后面继续遍历
     * @param path
     * @param name
     * @param content
     */
    private void persistenceHisLog(String path, String name, String content){
        try {
            overlapWriteFile(path,name,content);
        } catch (Exception e) {
            log.error("记录本次Author分析日志异常：{}",e);
        }
    }

    /**
     * 记录本次上报后的日志记录 下次从该记录行后面继续遍历
     */
    private Map<String,Object> getPersistenceHisLog(){
        Map<String,Object> map = new HashMap<>();
        try {
            File file = new File(sdkUtil.getLogPath()+"/"+Constant.AUTH_PERSISTENCE_LOG_HIS_FILE_NAME);
            if(!file.exists()){
                file.createNewFile();
            }
            BufferedReader in = new BufferedReader(new FileReader(sdkUtil.getLogPath()+"/"+Constant.AUTH_PERSISTENCE_LOG_HIS_FILE_NAME));
            String str;
            Long recordTime = 0L;//上次更新时间
            Long lines = 0L;//上次行数
            String fileName = "";//上次更新的文件名称
            while ((str = in.readLine()) != null) {
                String[] arr = str.split("\\|\\|");
                recordTime = new Long(arr[0]);
                lines = new Long(arr[1]);
                fileName = arr[2];
                break;
            }
            map.put("recordTime",recordTime);
            map.put("lines",lines);
            map.put("fileName",fileName);
        } catch (Exception e) {
            log.error("记录本次Author分析日志异常：{}",e);
        }
        return map;
    }

    /**
     * 覆盖原文件内容
     * @param path 文件路径
     * @param name 文件名称
     * @param content
     * @throws IOException
     */
    public static void overlapWriteFile(String path, String name, String content) {
        try {
            FileOutputStream fileOutputStream = null;
            File file = new File(path + name);
            if(!file.exists()){
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(content.getBytes("utf-8"));
            fileOutputStream.flush();
            fileOutputStream.close();
        }catch (Exception e){
            log.error("覆盖原文件内容失败：{}",e);
        }
    }

    /**
     * 原文件内容后追加
     * @param path 文件路径
     * @param name 文件名称
     * @param content
     * @throws IOException
     */
    public static void appendWriteFile(String path, String name, String content){
        try {
            path = path + name;
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path,true)));
            out.write(content);
            out.close();
        }catch (Exception e){
            log.error("原文件内容后追加失败：{}",e);
        }
    }

    /**
     * 查询文件夹下所有文件
     * @param path
     * @return
     */
    private List<File> getFileList(String path){
        File dir = new File(path);
        File[] files = dir.listFiles();
        List<File> fileList = new ArrayList<>();
        if(null != files){
            for(int i = 0; i < files.length; i++){
                String fileName = files[i].getName();
                if(files[i].isDirectory()){
                    fileList.addAll(getFileList(files[i].getAbsolutePath()));
                }else if(fileName.endsWith("log")){
//                    String strFileName = files[i].getAbsolutePath();
                    fileList.add(files[i]);
                }else{
                    continue;
                }
            }
        }
        return fileList;
    }

    /**
     * 按文件名称排序
     * @param filePath
     */
    private File[] orderByName(String filePath) {
        File file = new File(filePath);
        File[] files = file.listFiles();
        List fileList = Arrays.asList(files);
        Collections.sort(fileList, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                if (o1.isDirectory() && o2.isFile())
                    return -1;
                if (o1.isFile() && o2.isDirectory())
                    return 1;
                return o1.getName().compareTo(o2.getName());
            }
        });
        for (int i = 0; i < files.length; i++) {
            log.info("文件名称：{}-最后修改日期：{}",files[i].getName(),new Date(files[i].lastModified()));
        }
        return files;
    }

    /**
     * 按文件修改日期排序
     * @param filePath
     */
    private File[] orderByDate(String filePath) {
        File file = new File(filePath);
        File[] listFiles = file.listFiles();
        List<File> fileList = new ArrayList<>();
        if(null != listFiles){
            for(File f: listFiles){
                String name = f.getName();
                if(!StringUtil.isEmpty(name)){
                    String[] names=name.split("@");
                    if(null != names && names.length==2){//有效
                        fileList.add(f);
                    }
                }
            }
        }
        File[] files;
        if(!CollectionUtil.isEmpty(fileList)){
            files = fileList.toArray(new File[fileList.size()]);
            Arrays.sort(files, new Comparator<File>() {
                public int compare(File f1, File f2) {
                    long diff = f1.lastModified() - f2.lastModified();
                    if (diff > 0)
                        return 1;
                    else if (diff == 0)
                        return 0;
                    else
                        return -1;//如果 if 中修改为 返回-1 同时此处修改为返回 1  排序就会是递减
                }
                public boolean equals(Object obj) {
                    return true;
                }
            });
            for (int i = 0; i < files.length; i++) {
                log.info("文件名称：{}-最后修改日期：{}",files[i].getName(),new Date(files[i].lastModified()));
            }
            return files;
        }
        return null;
    }

    /**
     * 按文件大小排序
     * @param filePath
     */
    private File[] orderByLength(String filePath) {
        File file = new File(filePath);
        File[] files = file.listFiles();
        List<File> fileList = Arrays.asList(files);
        Collections.sort(fileList, new Comparator<File>() {
            public int compare(File f1, File f2) {
                long diff = f1.length() - f2.length();
                if (diff > 0)
                    return 1;
                else if (diff == 0)
                    return 0;
                else
                    return -1;//如果 if 中修改为 返回-1 同时此处修改为返回 1  排序就会是递减
            }
            public boolean equals(Object obj) {
                return true;
            }
        });
        for (int i = 0; i < files.length; i++) {
            log.info("文件名称：{}-最后修改日期：{}",files[i].getName(),new Date(files[i].lastModified()));
        }
        return files;
    }
}
